#include <bobox_manager.hpp>
#include <bobox_results.hpp>

#include "common_bbx/sharedBoxData/BinaryOperationArguments.h"
#include "common_bbx/tables/BoxDataTable.h"
#include "common_bbx/sharedBoxData/HashTableHolder.h"

#include <jmlib/cmdLineOptions/CmdLineParser.h>

#include "_unit_tests_/tests.h"

#include "models/generateModel.h"
#include "boxes/RootBox.h"
#include "boxes/BufferedOutputBox.h"
#ifdef BOBOX_VERSION_OLD
#include "../../../h/bofe_configuration.hpp"
#else

#endif

#include "../source/runtime/Runtime.h"



#include "models.h"
#include <vector>
#include <utility>
#include <functional>
#include <limits>

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>

#ifdef BOBOX_VERSION_OLD 

class configuration : public bofe::configuration
{
	virtual std::string get_value(const std::string &name) const
	{
		return ".";
	}
};

#endif


//class AppSettings {
//public:
//	static AppSettings& getInstance() {
//		AppSettings app;
//		return app;
//	}
//protected:
//	virtual ~AppSettings() { }
//private:
//	std::string model_;
//	int parallelism_;
//
//	AppSettings() {}
//};

// parallelism, lineEnd
// data[2], 
typedef std::vector<std::pair<std::string, 
	std::function<std::string(int, const std::string&)>>>  ModelList;


void runModel(const std::string& txtModel) {
#ifdef BOBOX_VERSION_OLD
	bobox::manager mng(true);
	configuration conf;
	jm4bbx::runtime rt;
	rt.init(conf);

	//ulibpp::uUINT64 start = ulibpp::system_info::get_relative_time();

	bobox::request_id_type rqid = mng.create_request(txtModel, &rt);
#endif
#ifdef BOBOX_VERSION_2_2
//	static bobox::manager mng(bobox::SS_SINGLE_THREADED);
	static bobox::manager mng(bobox::SS_SMP);
	jm4bbx::runtime rt;
	rt.init();

	std::istringstream stream(txtModel);
	bobox::model* m1 = bobox::good_old_parser::parse_model(stream, &rt);

	bobox::model_box::model* m2 = 
		new bobox::model_box::model(&rt, std::unique_ptr<bobox::model>(m1));

	bobox::request_id_type rqid = 
		mng.create_request(bobox::box_model_ptr_type(m2));
#endif

	mng.run_request(rqid);
	mng.wait_on_request(rqid);	
	const bobox::results *results = mng.get_results(rqid);
	mng.destroy_request(rqid);
}

void help() {
	std::cout
		<< "[-h]   [--help]" << std::endl << "\t" 
		<< "Zobrazi tuto napovedu." 
		<< std::endl << std::endl

		<< "[-r]   [--report]" << std::endl << "\t" 
		<< "Neprebehne vypocet len vypise zostrojeny model. Vyzaduje zadanie "
		<< "modelu viz -m a volitelne stupen paralelizacie viz -p." 
		<< std::endl << std::endl

		<< "[-l]   [--list]" << std::endl << "\t" 
		<< "Neprebehne vypocet len vypise zoznam dostupnych modelov." 
		<< std::endl << std::endl

		<< "[-m meno_modelu]   [--model meno_modelu]" << std::endl << "\t" 
		<< "Urcenie modelu, podla ktoreho bude prebiehat vypocet" 
		<< " - menom modelu v zozname. " 
		<< std::endl << std::endl


		<< "[-n cislo_modelu]   [--model_number cislo_modelu]" << std::endl << "\t" 
		<< "Urcenie modelu, podla ktoreho bude prebiehat vypocet"
		<< " - poradovym cislom v znozname. " 
		<< std::endl << std::endl


		<< "[-p stupen_paralelizacie]   [-parallelism stupen_paralelizacie] " 
		<< std::endl << "\t" 
		<< "Stupen paralelizacie urcuje maximalny mozny pocet paralelne " 
		<< "beziacich vypoctov. Zadavana hodnota musi byt prirodzene cislo "
		<< "od 1. Defaultne pouzity stupen paralelizacie je 2." 
		<< std::endl << std::endl

		<< "[-i]   [--interactive]" << std::endl << "\t" 
		<< "Spustenie programu v interaktivnom mode. Vsetky ostatne " 
		<< "argumenty z prikazoveho riadku budu ignorovane. Uzivatel bude "
		<< "dotazany na potrebne udaje. Umoznuje opakovany beh vypoctu." 
		<< std::endl << std::endl

		<< "[-s size]   [--hash-table-size size]" << std::endl << "\t" 
		<< "Nastavenie velkosti hasovacej tabulky. Hodnota size musi byt "
		<< "celociselna."
		<< std::endl << std::endl

		<< "[-b size]   [--buffer-size size]" << std::endl << "\t" 
		<< "Nastavenie velkosti bufferu v boxoch kt. bufferuju data."
		<< "Hodnota size musi byt kladna, nenulova celociselna."
		<< "Pre optimalitu vypoctu tiez dostatocne velka aby sa data neposielali prilis casto."
		<< std::endl << std::endl

		<< "[-e size]   [--exp-hash-table-size size]" << std::endl << "\t" 
		<< "Nastavenie velkosti hasovacej tabulky pre " 
		<< "experimantalne algoritmy s lokalnymi tabulkami. "
		<< "Hodnota size musi byt celociselna."
		<< std::endl << std::endl

		<< "[-a]   [--analyse-hashtable]" << std::endl << "\t" 
		<< "Po vykonani vypoctu podla modelu prebehne analyza hashovacej tabulky. "
		<< std::endl << std::endl


		<< "[-x]" << std::endl << "\t" 
		<< "Neoodalokovat data v hasovacej tabulke po ukonceni vypoctu. "

		<< "[-t]   [--test]" << std::endl << "\t" 
		<< "Spustenie testov. Testy vyuzivaju ODBC spojenie a zavisia na"
		<< " strukture tabuliek v DB. Pokial nie je vsetko ako ma byt testy"
		<< " skoncia chybovou hlaskou." 
		<< std::endl << std::endl


		<< "..." << std::endl;
}

void showModelList(const ModelList& ml) {
	std::cout << "Zoznam dostupnych modelov:" << std::endl;
	size_t counter = 0;
	for (size_t i = 0; i < ml.size(); ++i) {
		std::cout << "\t id: " << i << " - "<< ml[i].first << std::endl;
	}

}

void clearStabeleData() {
	jm4bbx::BinaryOperationArguments<jm4bbx::BoxDataTable>::getFirstArgument()->clear();
	jm4bbx::BinaryOperationArguments<jm4bbx::BoxDataTable>::getSecondArgument()->clear();
	jm4bbx::HashTableHolder<std::string>::getHashTable()->clear();
	jm4bbx::HashTableHolder<int>::getHashTable()->clear();
}

void analyseHashTable() {
	size_t sumCount = 0;
	jm4bbx::HashTableHolder<int>::getHashTable()->foreachExtended(
		[&sumCount](jm4bbx::HashTableHolder<int>::ExtendedHashEntry& entry) {						
			sumCount += entry.plainEntry.value.size();
	});


	const double lf = sumCount / (double) jm4bbx::HashTableHolder<int>::getHashTable()->getSize();
	// klasicky load factor je tu ako uniq load factor pretoze zaznamy sa zgrupuju
	// a tabulka o tom nevie
	const double ulf = jm4bbx::HashTableHolder<int>::getHashTable()->getLoadFactor();
	const double hlf = jm4bbx::HashTableHolder<int>::getHashTable()->getHashLoadFactor();
	std::cout << "Plain- load factor == " << lf << std::endl;
	std::cout << "Unique - load factor == " << ulf << std::endl;
	std::cout << "Hash- load factor == " << hlf << std::endl;
}

template<class Test>
void runTests() {
	Test t;
	for (size_t i = 1; i < t.size(); ++i) {
		runModel(t.runTest(i));
		clearStabeleData();
	}

}

void tests() {
	runTests<jm4bbx::IntegerHashJoinTest>();
	runTests<jm4bbx::ExperimentalJoinTest>();

	runTests<jm4bbx::IntegerHashDuplicityEliminationTest>();
	runTests<jm4bbx::IntegerSetHashIntersectionTest>();
	runTests<jm4bbx::IntegerBagHashIntersectionTest>();
	runTests<jm4bbx::IntegerFirstOpBagHashSubtractionTest>();
	runTests<jm4bbx::IntegerFirstOpSetHashSubtractionTest>();
	runTests<jm4bbx::IntegerSecondOpBagHashSubtractionTest>();
	runTests<jm4bbx::IntegerSecondOpSetHashSubtractionTest>();
}

void initModelList(ModelList& modelList) {
	using namespace std::placeholders;

	modelList.push_back(std::make_pair(
		"HashJoin-string-HardCodedData_1", 
		&jm4bbx::getStrHDHashJoinModel));

	modelList.push_back(std::make_pair(
		"Bag-HashIntersection-string-HardCodedData_1", 
		std::bind(jm4bbx::getStrHDHashIntersectionModel, _1, _2, false, true)));

	modelList.push_back(std::make_pair(
		"Set-HashIntersection-string-HardCodedData_1", 
		std::bind(jm4bbx::getStrHDHashIntersectionModel, _1, _2, false, false)));

	modelList.push_back(std::make_pair(
		"Bag-HashSubtraction-string-HardCodedData_1-SecondOperandHash", 
		std::bind(jm4bbx::getHDHashSecondSubtractionModel, _1, _2, false, true)));

	modelList.push_back(std::make_pair(
		"Bag-HashSubtraction-string-HardCodedData_1-FirstOperandHash", 
		std::bind(jm4bbx::getHDHashFirstSubtractionModel, _1, _2, false, true)));

	modelList.push_back(std::make_pair(
		"Set-HashSubtraction-string-HardCodedData_1-SecondOperandHash", 
		std::bind(jm4bbx::getHDHashSecondSubtractionModel, _1, _2, false, false)));

	modelList.push_back(std::make_pair(
		"Set-HashSubtraction-string-HardCodedData_1-FirstOperandHash", 
		std::bind(jm4bbx::getHDHashFirstSubtractionModel, _1, _2, false, false)));

	////////////////////////////////

	modelList.push_back(std::make_pair(
		"Bag-HashSubtraction-int-HardCodedData_1-SecondOperandHash", 
		std::bind(jm4bbx::getHDHashSecondSubtractionModel, _1, _2, true, true)));

	modelList.push_back(std::make_pair(
		"Bag-HashSubtraction-int-HardCodedData_1-FirstOperandHash", 
		std::bind(jm4bbx::getHDHashFirstSubtractionModel, _1, _2, true, true)));

	modelList.push_back(std::make_pair(
		"Set-HashSubtraction-int-HardCodedData_1-SecondOperandHash", 
		std::bind(jm4bbx::getHDHashSecondSubtractionModel, _1, _2, true, false)));

	modelList.push_back(std::make_pair(
		"Set-HashSubtraction-int-HardCodedData_1-FirstOperandHash", 
		std::bind(jm4bbx::getHDHashFirstSubtractionModel, _1, _2, true, false)));

	modelList.push_back(std::make_pair(
		"HashElimination-str-HardCodedData", 
		std::bind(jm4bbx::getStrHDEliminationModel, _1, _2)));

	modelList.push_back(std::make_pair(
		"Addition-int", 
		std::bind(jm4bbx::getIntAdditionModel, _1, _2)));

	modelList.push_back(std::make_pair(
		"Sum", 
		std::bind(jm4bbx::getSumModel, _1, _2)));

	modelList.push_back(std::make_pair(
		"Min", 
		std::bind(jm4bbx::getMinModel, _1, _2)));

	modelList.push_back(std::make_pair(
		"Max", 
		std::bind(jm4bbx::getMaxModel, _1, _2)));

	modelList.push_back(std::make_pair(
		"Avg", 
		std::bind(jm4bbx::getAvgModel, _1, _2)));
}

const char* csvBox = "CSV_BOX";
const char* hashIntBox = "HASH_INTEGER";
const char* joinBox = "CSV_BOX";
const char* intKeyRec = "IntegerKeyRecord";
const char* deadOutput = "DEAD_OUTPUT";

//jm4bbx::InputBoxConfiguration ccc[2] = { 
//	{"SELECT@*@FROM@data_2", 0}, {"SELECT@*@FROM@data_3", 0} };

jm4bbx::InputBoxConfiguration csvData[2] = {
	{"data.csv" , 0},
	{"data.csv" , 1} };


	//jm4bbx::InputBoxConfiguration csv1m[2] = {
	//	{"data_uniform_B.csv" , 0},
	//	{"data_uniform_B.csv" , 1} };
	//
	//jm4bbx::InputBoxConfiguration csv5m[2] = {
	//	{"data_uniform_C.csv" , 0},
	//	{"data_uniform_C.csv" , 1} };


	void addAggModel(ModelList& ml, jm4bbx::InputBoxConfiguration* csvSpec, 
		const char* mn, const char* aggFunName, const char* resultFunName) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, aggFunName, resultFunName] 
			(int p, const std::string& ln) -> std::string {

				return jm4bbx::generateAggregationFunctionModel(p, ln, 
					csvBox, csvSpec[0], aggFunName, resultFunName, 
					deadOutput);
			}));
	}



	void addArithmeticOpModel(ModelList& ml, 
		jm4bbx::InputBoxConfiguration* csvSpec, const char* mn, 
		const char* opName) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, opName] 
			(int p, const std::string& ln) -> std::string {

				return jm4bbx::generateArithmeticOperationModel(p, ln, 
					csvBox, csvSpec[0], csvSpec[1], opName, deadOutput, 
					intKeyRec);
			}));
	}


	void addExpModel(ModelList& ml, 
		jm4bbx::InputBoxConfiguration* csvSpec, const char* mn, 
		const char* operationName, bool bagVersion /*false*/) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, operationName, bagVersion] 
			(int p, const std::string& ln) -> std::string {

				return jm4bbx::generateExperimentalModel(p, ln, 
					csvBox, csvSpec[0], csvSpec[1], operationName, 
					deadOutput, "both",
					intKeyRec, bagVersion);
			}));
	}



	void add1StepModel(ModelList& ml, jm4bbx::InputBoxConfiguration* csvSpec, 
		const char* mn, const char* actionName) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, actionName] 
			(int p, const std::string& ln) -> std::string {

				//jm4bbx::RootBox::timeReportPrefix = 
				//	jmlib::convert<std::string>(p) + ";" +  mn;

				return jm4bbx::generateOneStepOnePassDbOperationModel(p, 
					ln, csvBox, csvSpec[0], actionName, deadOutput, 
					"first", intKeyRec);
			}));
	}

	void add2StepModel(ModelList& ml, jm4bbx::InputBoxConfiguration* csvSpec, 
		const char* mn, const char* actionName, bool bagVersion) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, actionName, bagVersion] 
			(int p, const std::string& ln) -> std::string {

				//jm4bbx::RootBox::timeReportPrefix = 
				//	jmlib::convert<std::string>(p) + ";" +  mn;

				return jm4bbx::generateTwoStepOnePassDbOperationModel(p, 
					ln, csvBox, csvSpec[0], csvSpec[1], hashIntBox, 
					actionName, deadOutput, "both", intKeyRec, 
					bagVersion);
			}));
	}


	void add3StepModel(ModelList& ml, jm4bbx::InputBoxConfiguration* csvSpec, 
		const char* mn, const char* actionName, const char* resultCreatorName, 
		bool bagVersion) {

			ml.push_back(std::make_pair(mn,
				[csvSpec, mn, actionName, resultCreatorName, bagVersion] 
			(int p, const std::string& ln) -> std::string {

				//jm4bbx::RootBox::timeReportPrefix = 
				//	jmlib::convert<std::string>(p) + ";" +  mn;

				return jm4bbx::generateThreeStepOnePassDbOperationModel(
					p, ln, csvBox, csvSpec[0], csvSpec[0], hashIntBox, 
					actionName, deadOutput, "first", intKeyRec, 
					bagVersion, resultCreatorName);
			}));
	}

	void initModelList2(ModelList& ml) {
		using namespace jm4bbx;

		addExpModel(ml, csvData, "Prep-join-bag", "EXPERIMENTAL_JOIN", true);
		addExpModel(ml, csvData, "Prep-prienik-bag", "EXPERIMENTAL_INTERSECTION", true);
		addExpModel(ml, csvData, "Prep-rozdiel-bag", "EXPERIMENTAL_SUBTRACTION", true);

		addExpModel(ml, csvData, "Prep-join-set", "EXPERIMENTAL_JOIN",  false);
		addExpModel(ml, csvData, "Prep-prienik-set", "EXPERIMENTAL_INTERSECTION", false);
		addExpModel(ml, csvData, "Prep-rozdiel-set", "EXPERIMENTAL_SUBTRACTION", false);

		// bez db operacie
		add2StepModel(ml, csvData, "Len zahasovat data", "NO_ACTION", false);
		// Agregacne fcie
		addAggModel(ml, csvData, "Agregacia-suma", "SUM_INTEGER", "SUM_RESULT_INTEGER");
		addAggModel(ml, csvData, "Agregacia-minimum", "MIN_INTEGER", "MIN_RESULT_INTEGER");
		addAggModel(ml, csvData, "Agregacia-maximum", "MAX_INTEGER", "MAX_RESULT_INTEGER");
		addAggModel(ml, csvData, "Agregacia-priemer", "AVG_INTEGER", "AVG_RESULT_INTEGER");
		// Aritmeticke operacie
		addArithmeticOpModel(ml, csvData, "Stlpec-sucet","ADDITION_INTEGER");
		addArithmeticOpModel(ml, csvData, "Stlpec-rozdiel","SUBTRACTION_INTEGER");
		addArithmeticOpModel(ml, csvData, "Stlpec-sucin","MULTIPLICATION_INTEGER");
		addArithmeticOpModel(ml, csvData, "Stlpec-podiel","DIVISION_INTEGER");
		// 1 step
		add1StepModel(ml, csvData, "Tabulka-eliminacia", "ELIMINATION_INTEGER");
		// 2 step
		add2StepModel(ml, csvData, "Tabulka-join", "HASH_JOIN_INTEGER", false);

		add2StepModel(ml, csvData, "Tabulka-prienik-set", "HASH_INTERSECTION_INTEGER", false);
		add2StepModel(ml, csvData, "Tabulka-prienik-bag", "HASH_INTERSECTION_INTEGER", true);

		add2StepModel(ml, csvData, "Tabulka-rozdiel-set(2 step)", "HASH_S_SUBTRACTION_INTEGER", false);
		add2StepModel(ml, csvData, "Tabulka-rozdiel-bag(2 step)", "HASH_S_SUBTRACTION_INTEGER", true);
		// 3 step
		add3StepModel(ml, csvData, "Tabulka-rozdiel-set(3 step)", "HASH_F_SUBTRACTION_INTEGER", "HASH_FR_SUBTRACTION_STRING", false);
		add3StepModel(ml, csvData, "Tabulka-rozdiel-bag(3 step)", "HASH_F_SUBTRACTION_INTEGER", "HASH_FR_SUBTRACTION_STRING", true);
	}


	int main(int argc, char *argv[]) {
		//tests();
		//return 0;
		//std::cout << std::numeric_limits<int>::min() << " : "<< std::numeric_limits<int>::max() << std::endl;
		// mapa<meno_modelu, funkcia_generujuca_model(stupen_paralelizmu, koniec_riadku)>
		ModelList modelList;

		initModelList2(modelList);
		using namespace jmlib;
		CmdLineParser parser;

		parser.addOptionDefinition("h").addAlias("help");	
		parser.addOptionDefinition("r").addAlias("report");
		parser.addOptionDefinition("l").addAlias("list");
		parser.addOptionDefinition("m", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("model");
		parser.addOptionDefinition("n", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("model_number");
		parser.addOptionDefinition("p", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("parallelism");
		parser.addOptionDefinition("i").addAlias("interactive");
		parser.addOptionDefinition("t").addAlias("test");
		parser.addOptionDefinition("s", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("hash-table-size");
		parser.addOptionDefinition("e", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("exp-hash-table-size");
		parser.addOptionDefinition("b", CmdLineOptionDefinition::ONE_REQUIRED).addAlias("buffer-size");
		parser.addOptionDefinition("a").addAlias("analyse-hashtable");
		parser.addOptionDefinition("x");
		//const int argc1 = 8;
		//char* argv1[argc1] = {"dipl.exe", "-n", "2", "-p", "8", "-s", "2000000"};
		//const int argc1 = 9;
		//char* argv1[argc1] = {"dipl.exe", "-p", "32", "-n", "0", "-b", "10000", "-s", "60000" };
		int argc1 = argc;
		char ** argv1 = argv;
		bool executeModel = true;
		try {
			parser.parseCmdLine(argc1, argv1);
			size_t hashTableSize = 0;
			// Nastavenie velkosti hashovacej tabulky.

			if (parser["s"]->isUsed()) {
				hashTableSize = parser["s"]->getValue<int>();
				//jm4bbx::HashTableHolder<std::string>::getHashTable()->realloc(hashTableSize);
				jm4bbx::HashTableHolder<int>::getHashTable()->realloc(hashTableSize);	
			}

			if (parser["e"]->isUsed()) {
				hashTableSize = parser["e"]->getValue<int>();
				jm4bbx::HashDBOperationBase::HASH_TABLE_SIZE = hashTableSize;
			}

			if (parser["b"]->isUsed()) {
				size_t dataChukSize = parser["b"]->getValue<size_t>();
				jm4bbx::BaseBufferedOutputBox::DEFAULT_CHUNK_SIZE = dataChukSize;
			}

			int paralelism = 2;
			int modelId = 0;
			bool working = true;
			while (working) {
				working = false;
				if (parser["i"]->isUsed() || argc1 == 1) {
					showModelList(modelList);
					std::cout << "Id modelu: " ;
					std::cin >> modelId;
					std::cout << "Stupen paralelizmu:";
					std::cin >> paralelism;
					std::cout << "Po vypocte opakovat vyber [ano==1/nie!=1]:";
					int repeat;
					std::cin >> repeat;
					working = repeat == 1;
				}
				else {

					// Detekcia modelu.
					if (parser["n"]->isUsed()) {
						modelId = parser["n"]->getValue<int>();
					}
					else if (parser["m"]->isUsed()) {
						// Neplatne id keby sa nenasiel model podla mena.
						modelId = modelList.size(); 
						std::string modelName = parser["m"]->getValue<std::string>();
						for (size_t i = 0; i < modelList.size(); ++i) {
							if (modelList[i].first == modelName) {
								modelId = i;
							}
						}
					}
					else if (parser["l"]->isUsed()) {
						showModelList(modelList);
						executeModel = false;
					}
					else if (parser["h"]->isUsed()) {
						help();
						executeModel = false;
					}
					else {
						throw "Vyzadovany je aspon jeden z prepinacov -m|-n|-l|-h.";
					}
					// Detekacia paralelizacie.
					if (parser["p"]->isUsed()) {
						paralelism = parser["p"]->getValue<int>(0);
					}
					else {
						// Default.
						paralelism = 2;
					}

					if (parser["r"]->isUsed()) {
						if (modelId >= modelList.size()) {
							throw "Neznamy model.";
						}
						std::cout << modelList[modelId].second(paralelism, "\n") 
							<< std::endl;
						executeModel = false;
					}
				}


				if (executeModel) {
					if (modelId >= modelList.size()) {
						throw "Nezname id modelu.";
					}
					JM_USE_EXPLICIT_LOGGER(ModelLogger)
						LOG_T_EX(ModelLogger, modelList[modelId].second(paralelism, "\n"))


						const std::string mn = modelList[modelId].first;



					jm4bbx::RootBox::timeReportPrefix = 
						jmlib::convert<std::string>(paralelism) + ";" +  mn + ";" 
						+ jmlib::convert<std::string>(hashTableSize) + ";"
						+ jmlib::convert<std::string>(jm4bbx::BaseBufferedOutputBox::DEFAULT_CHUNK_SIZE);
					runModel(modelList[modelId].second(paralelism, ""));
				}
				if (parser["a"]->isUsed()) {
					analyseHashTable();
				}

				if (!parser["x"]->isUsed()) {
					clearStabeleData();
				}
			}
		}
		catch (const char* xw) {
			std::cerr << xw << std::endl;
		}
		catch (const std::exception& x) {
			std::cerr << x.what() << std::endl << std::endl;
		}
		catch (...) {
			std::cerr << "..." << std::endl << std::endl;
			help();
		}

	}